﻿using System.Collections.Generic;
using MapEngine;
using System.Windows;
using System;
using System.Xml.Linq;
using GameEngine.Libs;

namespace GameEngine.Model.Data.implementation
{
    public class ViewVO<MyIdType> : IViewVO<MyIdType>
        where MyIdType : IComparable<MyIdType>
    {
        public IViewVOId<MyIdType> Id { get; protected set; }
        public IDictionary<IViewStateVO, IDictionary<IShapeVOId, IShapeVO>> Shapes { get; set; }

        public ViewVO(IViewVOId<MyIdType> id)
        {
            Id = id;
            Shapes = new Dictionary<IViewStateVO, IDictionary<IShapeVOId, IShapeVO>>();
            Shapes.Add(IViewVOConstants.DefaultState, new Dictionary<IShapeVOId, IShapeVO>());
        }

        public ViewVO(String serialized) {
            Shapes = new Dictionary<IViewStateVO, IDictionary<IShapeVOId, IShapeVO>>();
            DeSerialize(serialized);
        }

        public void AddShape(IShapeVO shape)
        {
            AddShape(shape,IViewVOConstants.DefaultState);
        }

        public void AddShape(IShapeVO shape, IViewStateVO state)
        {
            if(!Shapes.ContainsKey(state))
                Shapes.Add(state, new Dictionary<IShapeVOId, IShapeVO>());
            Shapes[state].Add(shape.Id,shape);
        }

        public string Serialize()
        {
            //return Serializer.Serialize(VO);
            XDocument doc = new XDocument();
            XElement mainNode = new XElement("ThingTypeVO");
            mainNode.SetAttributeValue("Class", GetType());

            {
                XElement node = new XElement("Id", new XAttribute("Class", Id.GetType()));
                node.Add(Id.Serialize());
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("Shapes");
                foreach (var row in Shapes)
                {
                    XElement rowXml = new XElement("State", new XAttribute("Class", row.Key.GetType()),  new XAttribute("State",row.Key.Value));
                    foreach (var row2 in row.Value)
                    {
                        XElement rowXml2 = new XElement("Shape", new XAttribute("Class", row2.Value.GetType()));
                        rowXml2.Add(row2.Value.Serialize());
                        rowXml.Add(rowXml2);
                    }
                    node.Add(rowXml);
                }
                mainNode.Add(node);
            }
            return mainNode.ToString();
        }

        public virtual void DeSerialize(string serializedString)
        {
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "Id":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType) as IViewVOId<MyIdType>;
                            instance.DeSerialize(node.Value);
                            Id = instance;
                        }
                        break;
                    case "Shapes":
                        {
                            foreach (var row in node.Elements())
                            {
                                var state = row.Attribute("State").Value;
                                var className = row.Attribute("Class").Value;
                                var classType = Type.GetType(className);
                                var instance = Activator.CreateInstance(classType, state) as IViewStateVO;
                                foreach (var row2 in row.Elements()) {
                                    var className2 = row2.Attribute("Class").Value;
                                    var classType2 = Type.GetType(className2);
                                    var instance2 = Activator.CreateInstance(classType2, row2.Value) as IShapeVO;
                                    AddShape(instance2, instance);
                                }
                            }
                        }
                        break;
                }
            }
        }
    }

    public class ViewVOId<MyIdType> : Id<MyIdType>, IViewVOId<MyIdType> where MyIdType : IComparable<MyIdType> {
        public ViewVOId(MyIdType id) : base(id) { }
        public ViewVOId() { }
    }

    public class ShapeVO : IShapeVO
    {
        public IShapeVOId Id { get; set; }
        public IShapeTypeVOId TypeId { get; set; }
        public object TypeModifiers { get; set; }

        public Point3d Position { get; set; }
        public Point3d Rotation { get; set; }
        public Point3d Scale { get; set; }

        public ShapeVO(IShapeVOId id, IShapeTypeVOId typeId)
        {
            Id = id;
            TypeId = typeId;
            Position = new Point3d();
            Scale = new Point3d(new Point(1, 1), 1);
        }

        public ShapeVO(String serialized){
        DeSerialize(serialized );;
        }

        public string Serialize()
        {
            //return Serializer.Serialize(VO);
            XDocument doc = new XDocument();
            XElement mainNode = new XElement("ThingTypeVO");
            mainNode.SetAttributeValue("Class", GetType());
            {
                XElement node = new XElement("Id", new XAttribute("Class", Id.GetType()));
                node.Add(Id.Value);
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("TypeId", new XAttribute("Class", TypeId.GetType()));
                node.Add(TypeId.Value);
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("TypeModifiers", new XAttribute("Class", TypeModifiers.GetType()));
                node.Add(TypeModifiers.ToString());
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("Position", new XAttribute("Class", Position.GetType()),
                    new XAttribute("Yaw", Position.Yaw.ToString()),
                    new XAttribute("Pitch", Position.Pitch.ToString()),
                    new XAttribute("Roll", Position.Roll.ToString()));
                mainNode.Add(node);
            }
            {
                if (Rotation != null)
                {
                    XElement node = new XElement("Rotation", new XAttribute("Class", Rotation.GetType()),
                        new XAttribute("Yaw", Rotation.Yaw.ToString()),
                        new XAttribute("Pitch", Rotation.Pitch.ToString()),
                        new XAttribute("Roll", Rotation.Roll.ToString()));
                    mainNode.Add(node);
                }
            }
            {
                if (Scale != null)
                {
                    XElement node = new XElement("Scale", new XAttribute("Class", Scale.GetType()),
                        new XAttribute("Yaw", Scale.Yaw.ToString()),
                        new XAttribute("Pitch", Scale.Pitch.ToString()),
                        new XAttribute("Roll", Scale.Roll.ToString()));
                    mainNode.Add(node);
                }
            }
            return mainNode.ToString();
        }

        public virtual void DeSerialize(string serializedString)
        {
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "Id":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType, node.Value) as IShapeVOId;
                            Id = instance;
                        }
                        break;
                    case "TypeId":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType, node.Value) as IShapeTypeVOId;
                            TypeId = instance;
                        }
                        break;
                    case "TypeModifiers":
                        {
                            //var className = node.Attribute("Class").Value;
                            //var classType = Type.GetType(className);
                            //var instance = Activator.CreateInstance(classType) as Object;
                            //TypeModifiers = instance;
                            TypeModifiers = node.Value;
                        }
                        break;
                    case "Position":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType,float.Parse(node.Attribute("Yaw").Value)
                                ,float.Parse(node.Attribute("Pitch").Value),
                                float.Parse(node.Attribute("Roll").Value)) as Point3d;
                            Position = instance;
                        }
                        break;
                    case "Rotation":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType, float.Parse(node.Attribute("Yaw").Value)
                                , float.Parse(node.Attribute("Pitch").Value),
                                float.Parse(node.Attribute("Roll").Value)) as Point3d;
                            Rotation = instance;
                        }
                        break;
                    case "Scale":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType, float.Parse(node.Attribute("Yaw").Value)
                                , float.Parse(node.Attribute("Pitch").Value),
                                float.Parse(node.Attribute("Roll").Value)) as Point3d;
                            Scale = instance;
                        }
                        break;
                }
            }
        }
    }

    public class ShapeVOId : SimpleId<string>, IShapeVOId{
    public ShapeVOId(string id) : base(id) { }
    public ShapeVOId() { }
    }

    public class ShapeTypeVO : IShapeTypeVO
    {
        public IShapeTypeVOId Id { get; protected set; }

        public ShapeTypeVO(IShapeTypeVOId id)
        {
            Id = id;
        }

        public ShapeTypeVO(String serialized){
            DeSerialize(serialized);
        }

        public string Serialize()
        {
            //return Serializer.Serialize(VO);
            XDocument doc = new XDocument();
            XElement mainNode = new XElement("ThingTypeVO");
            mainNode.SetAttributeValue("Class", GetType());

            {
                XElement node = new XElement("Id", new XAttribute("Class", Id.GetType()));
                node.Add(Id.Value);
                mainNode.Add(node);
            }
            return mainNode.ToString();
        }

        public virtual void DeSerialize(string serializedString)
        {
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "Id":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType, node.Value) as IShapeTypeVOId;
                            Id = instance;
                        }
                        break;
                }
            }
        }
    }

    public class ShapeTypeVOId : SimpleId<string>, IShapeTypeVOId{
    public ShapeTypeVOId(string id) : base(id) { }
    public ShapeTypeVOId() { }
    }

    public class Parameter
    {
        public string Name;
        public string Value;

        public Parameter(string name, string value)
        {
            Name = name;
            Value = value;
        }
    }
}
